module.exports = core;

const path = require('path')

const semver = require('semver')
const colors = require('colors/safe');
const userHome = require('user-home')
const pathExists = require('path-exists').sync
const commander = require('commander')

const log = require('@ting-cli-dev/log')
const init = require('@ting-cli-dev/init')
const exec = require('@ting-cli-dev/exec')
const pkg = require('../package.json')

let args, config;
const constant = require('./const')
const program = new commander.Command()

async function core(args) {
    try {
        // checkInputArgs()  有了 commander 就不需要解析参数了
        
        await prepare()
        registerCommand()

        
    } catch (error) {
        log.error(error.message)
        if (process.env.LOG_LEVEL === 'verbose') {
            console.log(error)
        }
    }
   
}

function registerCommand() {
    // 命令参数
    const options = program.opts();
    
    program
        .name(Object.keys(pkg.bin)[0])
        .usage('<command> [options]')
        .version(pkg.version)
        .option('-d --debug', '是否开启调试模式', false)
        .option('-tp, --targetPath <targetPath>', '是否指定本地调试路径', '')

    // 注册命令
    program
        .command('init [projectName]')
        .description('初始化项目')
        .option('-f --force', '是否强制初始化项目')
        .option('-np --noUpdate', '是否不更新包')
        .action(exec)
    
    log.verbose('全局 options', options)

    // 监听 debug 事件, 实现 debug 模式
    program.on('option:debug', function () {
        if (options.debug) {
            process.env.LOG_LEVEL = 'verbose'
        } else {
            program.env.LOG_LEVEL = 'info'
        }
        log.level = process.env.LOG_LEVEL
    })

    program.on('option:targetPath', function () {
        process.env.CLI_TARGET_PATH = options.targetPath
    })

    // 对未知命令的监听
    program.on('command:*', function (operation) {
        log.error(colors.red('未知命令：' + operation[0]))
        const avaliableCommander = program.commands.map(cmd => cmd.name())
        log.info('可用命令有：' + avaliableCommander.join(', '))
        program.exitCode = 1
    })

    program.parse(process.argv) // 必须有这行才能开启 option 监听

    // 没有输入命令就提示帮助手册 （必须放在参数解析的后面）
    if (program.args && program.args.length < 1) {
        program.outputHelp()
    }

}

// 脚手架启动准备阶段
async function prepare() {
    // checkNodeVersion(); // 检查node版本是不是大于最低要求（功能移入 init 包实现）

    checkPkgVersion();  // 判断脚手架版本
    checkRoot(); // 判断用户是不是root用户（root用户的话得降级）
    checkUserHome() // 判断用户的“用户目录”
    checkEnv()  // 检查环境变量（没有的话还得初始化环境变量）
    await checkGlobalUpdate() // 判断脚手架是否要提示更新
}

function checkPkgVersion() {
    //....
    const cliVersion = pkg.version; 
    log.info(cliVersion)
} 

function checkRoot() {
    // 防止 普通启动 和 sudo 启动(管理员方式执行)带来的权限差异
    // 不能用 root 账户， 不然的话做一些 文件操作会导致其他用户可能无法正常读写文件

    // console.log('uid: ', process.geteuid());
    // tips: root-check 2.0.0 版本是 import 语法
    const rootCheck = require('root-check');
    // 降低权限
    rootCheck();
    // console.log('uid: ', process.geteuid());

    // 降低权限的核心实现是
    // process.setegid
    // process.setuid
   
}

function checkUserHome() {
    if (!userHome || !pathExists(userHome)) {
        throw new Error(colors.red('当前登录用户主目录不存在！'))
    }
}

function checkEnv() {
    const dotenv = require('dotenv')
    const dotenvPath = path.resolve(userHome, '.env')
    if (pathExists(dotenvPath)) {
        // 从用户 /Users/leiting/.env 环境变量文件中读取环境变量， 并赋值给 proces.env
        dotenv.config({
            path: path.resolve(userHome, '.env')
        })  
    }
    createDefaultConfig()
}

function createDefaultConfig() {
    const cliConfig = {
        home: userHome,
    }
    if (process.env.CLI_HOME) {
        cliConfig['cliHome'] = path.join(userHome, process.env.CLI_HOME)
    } else {
        cliConfig['cliHome'] = path.join(userHome, constant.DEFAULT_CLI_HOME)
    }
    process.env.CLI_HOME_PATH = cliConfig.cliHome
}

async function checkGlobalUpdate() {
    // 1. 获取当前版本号和模块名
    const currentVersion = pkg.version;
    const npmName = pkg.name

    // 2. 调用所有版本号，对比哪些版本号是大于当前版本号的
    const { getNpmSemverVersion } = require('@ting-cli-dev/get-npm-info')
    // test 
    // const lastVerison = await getNpmSemverVersion('5.1.0', 'semver')
    const lastVerison = await getNpmSemverVersion(currentVersion, npmName)

    // 3. 获取最新版本号，提示用户更新到该版本
    if (lastVerison && semver.gt(lastVerison, currentVersion)) {
        log.warn(colors.green(`请手动更新${npmName} ，当前版本：${currentVersion}，最新版本：${lastVerison}， 更新命令：npm install ${npmName}`))
    } else {
        log.info(`${npmName} 已经是最新版，v${currentVersion}`)
    } 
}

/////// 废弃函数 命令参数检查， 可以移除minimist 库
// function checkInputArgs() {
//     const minimist = require('minimist')
//     args = minimist(process.argv.slice(2))
//     // console.log(args);
//     checkArgs()
// }

// function checkArgs() {
//     if (args.debug) {
//         process.env.LOG_LEVEL = 'verbose'
//     } else {
//         process.env.LOG_LEVEL = 'info'
//     }
//     log.level = process.env.LOG_LEVEL
// }



/***
 * lerna add user-home@2.0.0  core/cli 
 * 常用库
 * import-local 实现优先引入本地 NPM 包
 * npmlog 控制台日志打印（log 级别： info warn error）
 * semver  版本大小比较
 * colors  输出有颜色的字符串
 * root-check  跨平台实现读写权限降级
 * user-home  跨平台获取用户系统主目录
 * path-exists  判断文件路径是否存在
 * minimist node命令执行参数解析
 * dotenv  从.env文件中读取环境变量
 * url-join 4.0.1 根据给定的参数，拼接成一个url
 * commander   完整的 node.js 命令行解决方案。https://github.com/tj/commander.js/blob/HEAD/Readme_zh-CN.md
 * pkg-dir: 根据给定的路径找 package.json
 * npminstall:  安装npm包
 * 
 * inquirer: 命令行交互库 
 * 
 * lerna 基本操作
 * 1. 给某个模块装包
 *  lerna add user-home@2.0.0  core/cli 
 * 
 * 2. 创建一个模块
 *  lerna create get-npm-info utils/get-npm-info
 * 
 * 3. 引入一个本地包后，要去cli这个模块的文件夹去  npm link 下
 * 
 * 
 * 将一个文件变成可执行文件：  chmod +x 文件路径
 * 
 * spawn 异步执行耗时操作，执行过程可以不断有输出结果
 * exec/execFile 异步执行，但是只会在执行结束后返回结果  exesSyanc/execFileSync
 * fork: 会启动子进程，并默认用node的方式执行，适用于耗时的node操作
 * 
 * mac host 修改
 *     sudo vim /etc/hosts
 */